﻿using DiceRoller.Dice;
using Microsoft.Xna.Framework;
using System;
using System.ComponentModel;
using System.Windows.Controls;

namespace Roller.Animation
{
    /// <summary>
    /// Creates a UI element that is rendered representing a die that will be rolled.  
    /// Extends <see cref="UserControl"/> and implements <see cref="IRenderedDie"/>.
    /// </summary>
    /// <remarks>Current implementation requires that the parent / "viewing screen" be a canvas.</remarks>
    public partial class RenderedDie : UserControl, IRenderedDie
    {
        #region Fields

        private Vector2 position;
        private Vector2 velocity;

        #endregion

        #region Methods

        private void OnPropertyChanged( String propertyName )
        {
            if ( this.PropretyChanged != null )
            {
                this.PropretyChanged( this, new PropertyChangedEventArgs( propertyName ) );
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new default instance of the RenderedDie user control, and calls the InitializeComponent method.
        /// Position and Velocity are both created as Vector2.Zero.
        /// <param name="maximumValue">The maximum roll value that can be rendered by this instance.</param>
        /// </summary>
        public RenderedDie( int maximumValue )
        {
            InitializeComponent();

            this.DataContext = this;

            var random = new Random( DateTime.Now.Millisecond );
            var velocity1 = ( random.NextDouble() );
            var velocity2 = ( random.NextDouble() );

            this.Position = new Vector2( 20.0f, 20.0f );
            this.Velocity = new Vector2( (float) Math.Cos( ( random.NextDouble() * 10 ) ), (float) Math.Sin( ( random.NextDouble() * 10 ) ) ) * 5.0f;
            this.Die = new BoundedDie( maximumValue );
        }

        /// <summary>
        /// Creates a new instance of the RenderedDie at a specified X, Y location.
        /// </summary>
        /// <param name="maximumValue">The maximum roll value that can be rendered by this instance.</param>
        /// <param name="positionX"> An float value representing the required X coordinate.</param>
        /// <param name="positionY">An float value represnting the required Y coordinate.</param>
        /// <
        public RenderedDie( int maximumValue, float positionX, float positionY )
        {
            InitializeComponent();
            this.DataContext = this;

            var random = new Random( DateTime.Now.Millisecond );

            this.Position = new Vector2( positionX, positionY );
            this.Velocity = new Vector2( (float) Math.Cos ( ( random.NextDouble() * 10 ) ), (float) Math.Sin( ( random.NextDouble() * 10 ) ) );
            this.Die = new BoundedDie( maximumValue );
        }

        /// <summary>
        /// Creates a new instance of the RenderedDie at a specified X, Y location, as well as the Velocity X, Y values.
        /// </summary>
        /// <param name="maximumValue">The maximum roll value that can be rendered by this instance.</param>
        /// <param name="positionX"> An float value representing the required X coordinate.</param>
        /// <param name="positionY">An float value represnting the required Y coordinate.</param>
        /// <param name="velocityX">An float value representing the required X velocity.</param>
        /// <param name="velocityY">An float value representing the required Y velocity.</param>
        public RenderedDie( int maximumValue, float positionX, float positionY, float velocityX, float velocityY )
        {
            InitializeComponent();
            this.DataContext = this;

            this.Position = new Vector2( positionX, positionY );
            this.Velocity = new Vector2( velocityX, velocityY );
            this.Die = new BoundedDie( maximumValue );
        }

        #endregion

        #region IRenderedDie Members.

        #region Properties

        /// <summary>
        /// The die based object which manages the value "rolling" for the die.  This object will be referenced in order to generate the 
        /// roll value rendered to the screen.
        /// </summary>
        /// <value>A <see cref="BoundedDie"/> object.</value>
        public BoundedDie Die
        {
            get;
            set;
        }

        public String RollValue
        {
            get
            {
                return this.Die.LastRoll.ToString();
            }
        }

        /// <summary>
        /// The current position of the die in 2d space as rendered by the viewing element.
        /// </summary>
        /// <value>A <see cref="Vector2"/> object.</value>
        public Vector2 Position
        {
            get
            {
                return this.position;
            }
            set
            {
                this.position = value;

                this.SetValue( Canvas.TopProperty, Convert.ToDouble( value.Y ) );
                this.SetValue( Canvas.LeftProperty, Convert.ToDouble( value.X ) );
            }
        }

        /// <summary>
        /// The current velocity relative to the containing object of the die.  With the application of "science" and "physics"
        /// we will be able to replicate friction and other phenomena.
        /// </summary>
        /// <value>A <see cref="Vector2"/> object.</value>
        public Vector2 Velocity
        {
            get
            {
                return this.velocity;
            }
            set
            {
                this.velocity = value;
            }
        }


        #endregion

        #region Methods

        /// <summary>
        /// Method called once the Position and Velocity have been set.  Will trigger the "movement" of the object on 
        /// the canvas by adding the velocity to the position, generating a new position.
        /// </summary>
        public void Update()
        {
            this.Position += this.Velocity;
        }

        /// <summary>
        /// Method for "rolling" the die (utilizing the underlying <see cref="BoundedDie"/> object), and initializes the UI rendering / animation.
        /// </summary>
        public void Roll()
        {
            this.Die.Roll();

            this.Position += this.Velocity;
            this.RollValueDisplay.Text = this.Die.LastRoll.ToString();
        }

        #endregion

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropretyChanged;

        #endregion
    }
}
